// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
#include <stdio.h>
#include <queue>

#include "gtest/gtest.h"

// 是否为质数。
bool IsPrime(int n)
{
    if (n <= 1) return false;

    if (n % 2 == 0) return n == 2;
    for (int i = 3; ; i += 2) {
        if (i > n/i) break;
        if (n % i == 0) return false;
    }
    return true;
}

// 旧的参数化方式。
TEST(IsPrimeTest, HandleTrueReturn)
{
    EXPECT_TRUE(IsPrime(2));
    EXPECT_TRUE(IsPrime(3));
    EXPECT_TRUE(IsPrime(5));
    EXPECT_TRUE(IsPrime(11));
    EXPECT_TRUE(IsPrime(23));
    EXPECT_TRUE(IsPrime(17));
}

// 数值参数化。
class IsPrimeParamTest : public::testing::TestWithParam<int>
{

};

TEST_P(IsPrimeParamTest, HandleTrueReturn)
{
    int n =  GetParam();
    EXPECT_TRUE(IsPrime(n));
}

INSTANTIATE_TEST_SUITE_P(TrueReturn, IsPrimeParamTest, testing::Values(2, 3, 5, 11, 23, 17, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97));
// 第一个参数是测试案例的前缀，可以任意取。
// 第二个参数是测试案例的名称，需要和之前定义的参数化的类的名称相同，如：IsPrimeParamTest
// 第三个参数是可以理解为参数生成器，上面的例子使用test::Values表示使用括号内的参数。Google提供了一系列的参数生成的函数：
// Range(begin, end[, step])                                	范围在begin~end之间，步长为step，不包括end
// Values(v1, v2, ..., vN)                                  	v1,v2到vN的值
// ValuesIn(container) and ValuesIn(begin, end)	                从一个C类型的数组或是STL容器，或是迭代器中取值
// Bool()	                                                    取false 和 true 两个值
// Combine(g1, g2, ..., gN)	                                    这个比较强悍，它将g1,g2,...gN进行排列组合，g1,g2,...gN本身是一个参数生成器，
//                                                              每次分别从g1,g2,..gN中各取出一个值，组合成一个元组(Tuple)作为一个参数。

// 已知类型参数化。
template <class T>
std::queue<T>* CreateQueue();
template <>
std::queue<int>* CreateQueue<int>()
{
    return new std::queue<int>;
}
template <>
std::queue<char>* CreateQueue<char>()
{
    return new std::queue<char>;
}
template <>
std::queue<double>* CreateQueue<double>()
{
    return new std::queue<double>;
}

template <class T>
class QueueTest:public testing::Test
{
    protected:
        QueueTest():queue(CreateQueue<T>()) { }
        virtual ~QueueTest() {
            delete queue;
        }
        std::queue<T>* const queue;
};

// The list of types we want to test.
typedef testing::Types<int, char, double> Implementations;
TYPED_TEST_SUITE(QueueTest, Implementations);
TYPED_TEST(QueueTest, DefaultConstructor) {
   EXPECT_EQ(0u, this->queue->size()) << "queue size should be 0";
   this->queue->push(1);
   this->queue->push(2);
   this->queue->push(3);
   EXPECT_EQ(3u, this->queue->size()) << "queue size should be 3";
}

// 未知类型参数化。
template <class T>
class QueueTest2:public QueueTest<T>{
};

TYPED_TEST_SUITE_P(QueueTest2);
TYPED_TEST_P(QueueTest2, DefaultConstructor) {
   EXPECT_EQ(0u, this->queue->size());
}
REGISTER_TYPED_TEST_SUITE_P(QueueTest2, DefaultConstructor);
typedef testing::Types<int, char> Implementations1;
INSTANTIATE_TYPED_TEST_SUITE_P(QueueInt_Char, QueueTest2, Implementations1);

int main(int argc, char** argv) {
    testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
